#include "../../include/CacheTask.h"
#include "../../include/Logger.h"
#include "EventLoop.h"
#include "Acceptor.h"
#include "TcpConnection.h"
#include <unistd.h>
#include <sys/eventfd.h>
#include <iostream>
#include <utility>

using std::cout;
using std::endl;
using std::make_pair;

EventLoop::EventLoop(Acceptor &accptor)
: _epfd(createEpollFd())
, _evtfd(createEventFd())
, _evtlist(1024)
, _isLooping(false)
, _acceptor(accptor)
, _mutex()
,_timerfd(createTimerFd())
{
    //将listenfd放在红黑树上进行监听
    //看有没有新的连接请求上来
    //问题：如何获取listenfd（socket）
    //解决方案：可以在Acceptor类中设置fd()函数，
    //进而获取listenfd
    addEpollReadFd(_acceptor.fd());
    //eventfd返回的文件描述符_evtfd也需要进行监听
    addEpollReadFd(_evtfd);

    addTimerReadFd(_timerfd);
}

EventLoop::~EventLoop()
{
    close(_epfd);
    close(_evtfd);
}

//循环进行还是没有进行
void EventLoop::loop()
{
    _isLooping = true;
    while(_isLooping)
    {
        waitEpollFd();
    }
}

void EventLoop::unloop()
{
    _isLooping = false;
}

void EventLoop::setNewConnectionCallback(TcpConnectionCallback &&cb)
{
    _onNewConnectionCb = std::move(cb);
}

void EventLoop::setMessageCallback(TcpConnectionCallback &&cb)
{
    _onMessageCb = std::move(cb);
}

void EventLoop::setCloseCallback(TcpConnectionCallback &&cb)
{
    _onCloseCb = std::move(cb);
}

//封装epoll_wait的函数
void EventLoop::waitEpollFd()
{
    int nready = 0;
    do
    {
        nready = epoll_wait(_epfd, &*_evtlist.begin(), _evtlist.size(), 3000);
    }while(-1 == nready && errno == EINTR);

    if(-1 == nready)
    {
        //perror("waitEpollFd");
        LogError("waitEpollFd");
        return;
    }
    else if(0 == nready)
    {
        //cout << ">>epoll_wait timeout!!!" << endl;
        LogInfo(">>epoll_wait timeout!!!");
    }
    else
    {
        //如果客户端的连接请求非常的多，多到马上要超过1024了，
        //所以_evtList需要进行扩容，而现在没有自动扩容的能力
        if(nready == (int)_evtlist.size())
        {
            _evtlist.resize(2 * nready);
        }

        for(int idx = 0; idx < nready; ++idx)
        {
            int fd = _evtlist[idx].data.fd;
            //有新的连接请求
            if(fd == _acceptor.fd())
            {
                if(_evtlist[idx].events & EPOLLIN)
                {
                    //处理新的连接
                    handleNewConnection();
                }
            }
            else if(fd == _evtfd)//监听的文件描述符_evtfd
            {
                handleRead();
                doPengdingFunctors();
            } else if(fd == _timerfd) {
                handleTimerRead();
                doCacheFunctor();
            }
            else
            {
                if(_evtlist[idx].events & EPOLLIN)
                {
                    //处理消息的收发
                    handleMessage(fd);
                }

            }
        }
    }
}

//处理新的连接
void EventLoop::handleNewConnection()
{
    int connfd = _acceptor.accept();
    if(connfd < 0)
    {
        //perror("handleNewConnection accept");
        LogError("handleNewConnection accept");
        return;
    }

    //将connfd放在红黑树上进行监听
    addEpollReadFd(connfd);

    //如果connfd有正确返回结果，就表明三次握手建立成功
    /* TcpConnection con(connfd); */
    TcpConnectionPtr con(new TcpConnection(connfd, this));

    //TCP网络编程处理的三个半事件(注册)
    con->setNewConnectionCallback(_onNewConnectionCb);//连接建立事件的注册
    con->setMessageCallback(_onMessageCb);//消息到达事件的注册
    con->setCloseCallback(_onCloseCb);//连接断开事件的注册
    
    //将connfd与TcpConnection的键值对存放在map中
    /* _conns[connfd] = con;//ok */
    _conns.insert(make_pair(connfd, con));//ok

    //连接建立的事件的执行时机到了，需要执行
    con->handleNewConnectionCallback();
}

//处理消息的收发
void EventLoop::handleMessage(int fd)
{
    //1、首先通过fd找到连接
    auto iter = _conns.find(fd);
    if(iter != _conns.end())
    {
        //2、然后再通过连接来查找是否断开
        bool flag = iter->second->isClosed();
        if(flag)
        {
            //2.1、如果断开就应该执行连接断开的事件
            iter->second->handleCloseCallback();
            delEpollReadFd(fd);//将文件描述符从红黑树上摘除
            _conns.erase(iter);//既然连接已经不存在了，就需要将其从map中删除
        }
        else
        {
            //2.2、如果没有断开，就表明可以持续发数据，也就是消息到达的事件
            iter->second->handleMessageCallback();
        }
    }
    else
    {
        //cout << "该连接不存在" << endl;
        LogError("该连接不存在");
        return;
    }
}

//创建文件描述符_epfd
int EventLoop::createEpollFd()
{
    int fd = ::epoll_create1(0);
    if(fd < 0)
    {
        //perror("epoll_create1");
        LogInfo("epoll_create1");
        return fd;
    }

    return fd;
}

//将文件描述符放在红黑树上进行监听
void EventLoop::addEpollReadFd(int fd)
{
    struct epoll_event evt;
    evt.events = EPOLLIN;
    evt.data.fd = fd;

    int ret = ::epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &evt);
    if(ret < 0)
    {
        //perror("addEpollReadFd epoll_ctl");
        LogError("addEpollReadFd epoll_ctl");
        return;
    }
}

//将文件描述符从红黑树上摘除
void EventLoop::delEpollReadFd(int fd)
{
    struct epoll_event evt;
    evt.events = EPOLLIN;
    evt.data.fd = fd;

    int ret = ::epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, &evt);
    if(ret < 0)
    {
        //perror("delEpollReadFd epoll_ctl");
        LogError("delEpollReadFd epoll_ctl");
        return;
    }
}
void EventLoop::wakeup()
{
    uint64_t one = 1;
    ssize_t ret = ::write(_evtfd, &one, sizeof(one));
    if(ret != sizeof(one))
    {
        //perror("wakeup");
        LogError("wakeup");
        return;
    }
}

void EventLoop::handleRead()
{
    uint64_t one = 1;
    ssize_t ret = ::read(_evtfd, &one, sizeof(one));
    if(ret != sizeof(one))
    {
        //perror("handleRead");
        LogError("handleRead");
        return;
    }
}

int EventLoop::createEventFd()
{
    int fd = eventfd(10, 0);
    if(fd < 0)
    {
        //perror("createEventFd");
        LogError("createEventFd");
        return fd;
    }
    return fd;
}

void EventLoop::doPengdingFunctors()
{
    vector<Functor> tmp;
    {
        MutexLockGuard autoLock(_mutex);
        tmp.swap(_pengdings);
    }

    for(auto &cb : tmp)
    {
        cb();//执行所有的"任务"
    }
}

void EventLoop::runInLoop(Functor &&cb)
{
    {
        MutexLockGuard autoLock(_mutex);
        _pengdings.push_back(std::move(cb));
    }

    wakeup();//唤醒EventLoop执行"任务"
}

//创建timer的文件描述符
int EventLoop::createTimerFd()
{
    int fd = timerfd_create(CLOCK_REALTIME, 0);
        if(fd < 0)
    {
        //perror("createTimerFd");
        LogError("createTimerFd");
        return fd;
    }
    struct itimerspec value;
    value.it_value.tv_sec = 5; // 设置起始时间（秒）
    value.it_value.tv_nsec = 0;

    value.it_interval.tv_sec = 1; // 设置间隔时间（秒）
    value.it_interval.tv_nsec = 0;

    // 设置 timerfd 文件描述符的定时器参数
    int ret = timerfd_settime(fd, 0, &value, nullptr);
    if (ret < 0)
    {
        //perror("timerfd_settime");
        LogError("timerfd_settime");
        return fd;
    }

    return fd;
}

//将timer描述符放在红黑树上进行监听
void EventLoop::addTimerReadFd(int fd)
{
    struct epoll_event tm;
    tm.events = EPOLLIN;
    tm.data.fd = fd;

    int ret = epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &tm);
    if(ret < 0)
    {
        //perror("epoll_ctl add timer");
        LogError("epoll_ctl add timer");
        return;
    }
}

void EventLoop::handleTimerRead()
{
        uint64_t one = 1;
    ssize_t ret = ::read(_timerfd, &one, sizeof(one));
    if(ret != sizeof(one))
    {
        //perror("read");
        LogError("read");
        return;
    }
}

void EventLoop::doCacheFunctor()
{
    CacheTask task;
    auto func = std::bind(&CacheTask::process,&task);
    func();
}
